package org.nanhill.commons.collection;

import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.HashMap;

/**
 * Read Write Map.
 * 
 * Write is expensive. Read is fast as pure HashMap.
 * 
 * @author hailong.wang [whlhuzhao at hotmail dot com]
 * 
 */
public class ReadWriteMap<K, V> implements Map<K, V> {
	protected volatile Map<K, V> mapToRead = getNewMap();

	// you can override it as new TreeMap();
	protected Map<K, V> getNewMap() {
		return new HashMap<K, V>();
	}

	// copy mapToWrite to mapToRead
	protected Map<K, V> copy() {
		Map<K, V> newMap = getNewMap();
		newMap.putAll(mapToRead);
		return newMap;
	}

	// read methods
	public int size() {
		return mapToRead.size();
	}

	public boolean isEmpty() {
		return mapToRead.isEmpty();
	}

	public boolean containsKey(Object key) {
		return mapToRead.containsKey(key);
	}

	public boolean containsValue(Object value) {
		return mapToRead.containsValue(value);
	}

	public Collection<V> values() {
		return mapToRead.values();
	}

	public Set<Map.Entry<K, V>> entrySet() {
		return mapToRead.entrySet();
	}

	public Set<K> keySet() {
		return mapToRead.keySet();
	}

	public V get(Object key) {
		return mapToRead.get(key);
	}

	// write methods
	public synchronized void clear() {
		mapToRead = getNewMap();
	}

	public synchronized V remove(Object key) {
		Map<K, V> map = copy();
		V o = map.remove(key);
		mapToRead = map;
		return o;
	}

	public synchronized V put(K key, V value) {
		Map<K, V> map = copy();
		V o = map.put(key, value);
		mapToRead = map;
		return o;
	}

	public void putAll(Map<? extends K, ? extends V> t) {
		Map<K, V> map = copy();
		map.putAll(t);
		mapToRead = map;
	}

}
